package com.ying.rabbitmqspringbootconsumer.listener;

import com.rabbitmq.client.Channel;
import com.ying.rabbitmqspringbootconsumer.util.RedisUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;

/**
 * ClassName: IdempotenceListener
 * Package: com.ying.rabbitmqspringbootconsumer.listener
 * Description:
 *
 * @Author 刘英杰
 * @Create 2025/7/24 22:57
 * @Version 1.0
 */

@Component
public class IdempotenceListener {

    @Autowired
    RedisUtils redisUtils;

    @RabbitListener(queues = "idempotenceQueue")
    public void idempotenceQueue(Message message, Channel channel) {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            System.out.println(new String (message.getBody()));

            //1.在消费前,根据messageID去redis查询看是否有这条消息
            //如果有,说明之前已经消费过,不再消费
            //如果没有,再消费
            String messageId = message.getMessageProperties().getMessageId();

            if (StringUtils.isEmpty(redisUtils.get(messageId))) {
                //模拟根据message中的内容{quantity:3}去数据库扣库存
                System.out.println("减少库存");
                //首次消费,将messageID=messageBody存入数据库
                redisUtils.set(messageId,new String(message.getBody()));

                channel.basicAck(deliveryTag, true);
            }else {
                System.out.println("消息已经被消费");
                //丢弃重复的消息,requeue=false
                channel.basicNack(deliveryTag,true,false);
            }

        } catch (Exception e) {

            try {
                //4.拒绝确认:告诉RabbitMQ消费失败
                /**
                 * deliveryTag:消息的唯一标识,从1开始计数
                 * multiple:批量拒签消息
                 * requeue:true,重新放回队列,消费者会重新消费该消息
                 */

                channel.basicNack(deliveryTag,true,true);
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
}
